#ifndef __VECTOR_HPP__
#define __VECTOR_HPP__

#include "math/math_config.h"
#include "util/utils.h"
#include "util/allocator.hpp"
#include <string.h>

NS_MATH_BEGIN

template<typename T, typename S=int32, typename allocator=xphysics::util::standard_allocator<T> >
class vector : public allocator
{
public:
	typedef T value_type;
	typedef T& reference;
	typedef const T& const_reference;
	typedef S size_type;
	typedef vector<T> this_type;

	typedef value_type* iterator;
	typedef const value_type* const_iterator;

	static const int npos = -1;

protected:
	value_type* m_data;
	size_type m_size;
	size_type m_capacity;

public:
	vector():m_data(NULL),m_size(0),m_capacity(0){}
	vector(size_type size, const value_type& val = value_type()):m_size(size),m_data(NULL),m_capacity(size)
	{
		if(m_size>0)
		{
			m_data = create(m_size);
			for(size_type i=0;i<m_size;++i)m_data[i]=val;
		}
	}
	vector(const this_type& vec):m_data(NULL),m_size(vec.m_size),m_capacity(vec.m_capacity)
	{
		if(m_size>0)
		{
			m_data = create(m_size);
			__memcopy(m_data, vec.m_data, m_size);
		}
	}
	vector(this_type&& vec):m_data(NULL),m_size(0),m_capacity(0)
	{
		swap(vec);
	}
	~vector(){destroy(m_data);}

public:
	inline size_type size()const{return m_size;}
	inline size_type capacity()const{return m_capacity;}
	inline value_type* ptr(){return m_data;}
	inline const value_type* ptr()const{return m_data;}
	bool empty()const{return !m_data;}

	reference operator[](size_type idx){return m_data[idx];}
	const_reference operator[](size_type idx)const{return m_data[idx];}

public:
	void push_back(const value_type& val)
	{
		if(m_size<m_capacity)
		{
			m_data[m_size]=val;
			m_size++;
		}else
		{
			size_type new_capacity = __expand(m_capacity);
			value_type* tmp_data = create(new_capacity);
			memcpy(tmp_data, m_data, sizeof(value_type)*m_size);
			destroy(m_data);
			m_data = tmp_data;
			m_data[m_size] = val;
			m_size++;
			m_capacity = new_capacity;
		}
	}

	void push_back(const value_type& val0, const value_type& val1)
	{
		push_back(val0);
		push_back(val1);
	}

	void push_back(const value_type& val0, const value_type& val1, const value_type& val2)
	{
		push_back(val0, val1);
		push_back(val2);
	}

	void push_back(const this_type& vec)
	{
		size_type old_size = m_size;
		resize(m_size+vec.m_size);
		__memcopy(m_data+old_size, vec.m_data, vec.m_size);
	}

	void extend(const this_type& vec)
	{
		push_back(vec);
	}

	value_type pop_back()
	{
		m_size--;
		return m_data[m_size];
	}

	void reserve(size_type new_capacity)
	{
		if(new_capacity>m_capacity)
		{
			value_type* tmp_data = create(new_capacity);
			memcpy(tmp_data, m_data, sizeof(value_type)*m_size);
			destroy(m_data);
			m_data = tmp_data;
		}
	}

	void resize(size_type new_size)
	{
		if(new_size<=m_capacity)
		{
			m_size=new_size;
		}else
		{
			reserve(new_size);
			m_size = new_size;
		}
	}

	inline iterator begin(){return m_data;}
	inline iterator end(){return m_data+m_size;}
	inline const_iterator begin()const{return m_data;}
	inline const_iterator end()const{return m_data+m_size;}

	inline reference first(){return m_data[0];}
	inline const_reference first()const{return m_data[0];}
	inline reference last(){return m_data[m_size-1];}
	inline const_reference last()const{return m_data[m_size-1];}

	size_type find(const_reference val)const
	{
		for(int i=0;i<m_size;++i)
		{
			if(m_data[i]==val)return i;
		}
		return npos;
	}

	void clear()
	{
		m_size = 0;
	}

	void xclear()
	{
		swap(this_type());
	}

	void swap(this_type& vec)
	{
		using namespace xphysics::util;
		xswap(m_data, vec.m_data);
		xswap(m_size, vec.m_size);
		xswap(m_capacity, vec.m_capacity);
	}

	this_type& operator= (const this_type& vec)
	{
		this_type tmp(vec);
		swap(tmp);
		return *this;
	}

	this_type& operator= (this_type&& tmp_vec)
	{
		swap(tmp_vec);
		return *this;
	}
};


NS_MATH_END

#endif